﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Net.NetworkInformation;
using IOT_Config;

namespace WindowsFormsApplication1
{
    public partial class ComAssistant : Form
    {
        private SerialPort serialPort;
        private Boolean isSerialOpened = false;
        private Color preColor;
        private readonly object balanceLock = new object();
        private List<COMPortInfo> comports;
        private List<IOTDevice> deviceList;
        private List<AsyncSocketUDPServer> udpServers;

        private delegate void UpdateDeviceList(IOTDevice device);
        private UpdateDeviceList UpdateDeviceHandler;



        private int[] serialBauds = new int[] {4800 ,9600, 14400, 19200,
                            38400, 56000, 57600, 115200,
                            128000, 230400, 256000, 460800 };
        private string[] dataBits = new string[] { "5", "6", "7", "8", "9" };
        private string[] parityMode = new string[] { "None", "Odd", "Even", "Mark", "Space" };
        private string[] stopBits = new string[] { "0.5", "1", "1.5", "2" };

        private IOTDevice curDevice;

        public ComAssistant()
        {
            InitializeComponent();

            preColor = button_Serial.BackColor;

            comboBox_SerialPort.Items.Clear();
            comports = COMPortInfo.GetCOMPortsInfo();
            comports.Sort();
            foreach (var port in comports)
            {
                comboBox_SerialPort.Items.Add(port.Name + " - " + port.Description);
            }

            /* 模块工作模式 */
            comboBox_WorkMode.Items.Add("UDP Client");
            comboBox_WorkMode.Items.Add("TCP Client");
            comboBox_WorkMode.Items.Add("UDP Server");
            comboBox_WorkMode.Items.Add("TCP Server");

            /* 模块IP模式 */
            comboBox_IPMode.Items.Add("DHCP");
            comboBox_IPMode.Items.Add("Static");

            /* 串口波特率 */
            string[] bauds = Array.ConvertAll(serialBauds, ele => ele.ToString());
            comboBox_SerialBaud.Items.AddRange(bauds);
            comboBox_SerialDataBits.Items.AddRange(dataBits);
            comboBox_SerialParity.Items.AddRange(parityMode);
            comboBox_SerialStopBits.Items.AddRange(stopBits);

            /* 设备列表 */
             deviceList = new List<IOTDevice>();

            /* enum network card */
            udpServers = new List<AsyncSocketUDPServer>();
            EnumNetworkCard();

            /* 添加列表更新服务函数 */
            UpdateDeviceHandler = new UpdateDeviceList(UpdateDeviceListMethod);

            /* 显示设备列表头信息 */
            listView_DeviceList.HeaderStyle = ColumnHeaderStyle.Clickable;
            listView_DeviceList.View = View.Details;
            listView_DeviceList.Columns.Add("MAC 地址", 250, HorizontalAlignment.Left);
        }

        private void EnumNetworkCard()
        {
            List<IPAddress> netcardAddress = new List<IPAddress>();

            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); //get all network interfaces of the computer
            foreach (NetworkInterface adapter in nics)
            {
                // Only select interfaces that are Ethernet type and support IPv4 (important to minimize waiting time)
                if (adapter.NetworkInterfaceType != NetworkInterfaceType.Ethernet) { continue; }
                if (adapter.Supports(NetworkInterfaceComponent.IPv4) == false) { continue; }
                try
                {
                    IPInterfaceProperties adapterProperties = adapter.GetIPProperties();
                    foreach (var ua in adapterProperties.UnicastAddresses)
                    {
                        if (ua.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            IPEndPoint localEP = new IPEndPoint(ua.Address, 8000);
                            AsyncSocketUDPServer udpServer = new AsyncSocketUDPServer(localEP);
                            udpServer.DataReceived += UdpDataReceived;
                            udpServer.Start();

                            udpServers.Add(udpServer);
                        }
                    }     
                }
                catch {}
            }
        }

        private void UdpDataReceived(object sender, AsyncSocketUDPEventArgs e)
        {
            int len = e._state.length;
            byte[] buffer = new byte[len];

            Array.Copy(e._state.buffer, buffer, len);

            /* 解析数据包到IOTDevice实例 */
            IOTDevice device = IOTDevice.Parse(e._state.buffer);
            device.configEndPoint = e._state.remote;

            this.Invoke(UpdateDeviceHandler, device);

            Console.WriteLine(BitConverter.ToString(buffer));
        }

        private void UpdateDeviceListMethod(IOTDevice newDevice)
        {
            foreach (var device in deviceList)
            {
                /* 设备已经在deviceList中 */
                if (newDevice.moduleID == device.moduleID)
                {
                    /* 设备是界面选中设备 */
                    if (curDevice == device)
                    {
                        curDevice = newDevice;
                        Update_UI_Info(newDevice);
                    }

                    /* 更新设备 */
                    deviceList.Remove(device);
                    deviceList.Add(newDevice);

                    return;
                }
            }

            /* 新设备，未在deviceList列表中 */
            deviceList.Add(newDevice);

            listView_DeviceList.BeginUpdate();

            ListViewItem deviceItem = new ListViewItem();
            deviceItem.Text = BitConverter.ToString(newDevice.macAddr);
            listView_DeviceList.Items.Add(deviceItem);

            listView_DeviceList.EndUpdate();
        }

        private void button_NetScan_Click(object sender, EventArgs e)
        {
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Broadcast, 7000);

            foreach (var udpServer in udpServers)
            {
                udpServer.Send("ping!", endpoint);
            }
        }

        private void button_Serial_Click(object sender, EventArgs e)
        {
            try
            {
                string comboBox_Text = comboBox_SerialPort.Text;
                string portName = comboBox_Text.Substring(0, comboBox_Text.LastIndexOf(" -"));
                if (!isSerialOpened)
                {
                    serialPort = new SerialPort(portName);
                    serialPort.Open();

                    button_Serial.BackColor = Color.Red;
                    button_Serial.Text = "断开串口";
                    isSerialOpened = true;
                }
                else
                {
                    if (serialPort != null)
                    {
                        if (serialPort.IsOpen)
                            serialPort.Close();
                    }
                    button_Serial.BackColor = preColor;
                    button_Serial.Text = "打开串口";
                    isSerialOpened = false;
                }

            }
            catch (UnauthorizedAccessException ex)
            {}
        }

        private void Update_ComDevice_List()
        {
            comboBox_SerialPort.Items.Clear();
            List<COMPortInfo> comports = COMPortInfo.GetCOMPortsInfo();
            comports.Sort();
            foreach (var port in comports)
            {
                comboBox_SerialPort.Items.Add(port.Name + " - " + port.Description);
            }
        }

        private void comboBox_SerialPort_MouseClick(object sender, MouseEventArgs e)
        {
            Update_ComDevice_List();
        }

        private void listView_DeviceList_MouseClick(object sender, MouseEventArgs e)
        {
            int selectCount = listView_DeviceList.SelectedItems.Count;
            if (selectCount == 0)
                return;

            /* 更新复选框 */
            foreach (ListViewItem item in listView_DeviceList.Items)
                item.Checked = false;

            listView_DeviceList.SelectedItems[0].Checked = true;

            button_Save.Enabled = true;


            /* 更新信息到信息表 */
            string selectedMacAddr = listView_DeviceList.SelectedItems[0].Text;
            foreach (var device in deviceList)
            {
                string macAddr = BitConverter.ToString(device.macAddr);
                if (macAddr == selectedMacAddr)
                {
                    /* 记录当前设备 */
                    int index = deviceList.IndexOf(device);
                    curDevice = deviceList[index];

                    Update_UI_Info(curDevice);
                }
            }
        }

        private void Update_UI_Info(IOTDevice device)
        {
            /* 更新设备信息到界面 */
            textBox_ModuleIPAddr.Text = device.localIP.ToString();
            textBox_LocalPort.Text = device.localPort.ToString();
            textBox_NetMask.Text = device.netmask.ToString();
            textBox_Gateway.Text = device.gateway.ToString();

            textBox_RemoteIPAddr.Text = device.remoteIP.ToString();
            textBox_RemotePort.Text = device.remotePort.ToString();

            comboBox_WorkMode.SelectedIndex = (int)device.moduleMode;
            comboBox_IPMode.SelectedIndex = (int)device.ipMode;
            comboBox_SerialBaud.SelectedIndex = Array.IndexOf(serialBauds, device.iotSerial.baudrate);
            comboBox_SerialDataBits.SelectedIndex = (int)device.iotSerial.dataWidth;
            comboBox_SerialParity.SelectedIndex = (int)device.iotSerial.parity;
            comboBox_SerialStopBits.SelectedIndex = (int)device.iotSerial.stopBits;
        }

        private void button_Save_Click(object sender, EventArgs e)
        {
            if (curDevice == null)
                return;

            /* 刷新界面内容 */
            ListViewItem selectedItem = listView_DeviceList.SelectedItems[0];
            listView_DeviceList.Items.Remove(selectedItem);
            deviceList.Remove(curDevice);
            button_Save.Enabled = false;

            /* 模块工作模式 */
            int workModeIdx = comboBox_WorkMode.SelectedIndex;
            curDevice.moduleMode = (ModuleMode)Enum.ToObject(typeof(ModuleMode), workModeIdx);

            /* 模块IP模式 */
            int ipModeIdx = comboBox_IPMode.SelectedIndex;
            curDevice.ipMode = (IPMode)Enum.ToObject(typeof(IPMode), ipModeIdx);

            /* 模块IP地址 */
            string lcoalIPAddr = textBox_ModuleIPAddr.Text;
            curDevice.localIP = IPAddress.Parse(lcoalIPAddr);

            /* 子网掩码 */
            string netmask = textBox_NetMask.Text;
            curDevice.netmask = IPAddress.Parse(netmask);

            /* 网关IP地址 */
            string gateway = textBox_Gateway.Text;
            curDevice.gateway = IPAddress.Parse(gateway);

            /* DNS服务器 */
            //string dns = textBox_DNSServer.Text;
            //curDevice.dnsServer = IPAddress.Parse(dns);

            /* 模块端口 */
            string localPortStr = textBox_LocalPort.Text;
            curDevice.localPort = Convert.ToUInt16(localPortStr, 10);

            /* 远程IP1 */
            string remoteIP1Addr = textBox_RemoteIPAddr.Text;
            curDevice.remoteIP = IPAddress.Parse(remoteIP1Addr);

            /* 远程Port1 */
            string remotePort1Str = textBox_RemotePort.Text;
            curDevice.remotePort = Convert.ToUInt16(remotePort1Str, 10);

            /* 串口配置信息 */
            string baudrateStr = comboBox_SerialBaud.Text;
            curDevice.iotSerial.baudrate = Convert.ToInt32(baudrateStr, 10);

            int dataWidthIndex = comboBox_SerialDataBits.SelectedIndex;
            curDevice.iotSerial.dataWidth = (SerialDataWidth)Enum.ToObject(typeof(SerialDataWidth), workModeIdx);

            int parityIndex = comboBox_SerialParity.SelectedIndex;
            curDevice.iotSerial.parity = (SerialParity)Enum.ToObject(typeof(SerialParity), parityIndex);

            int stopBitsIndex = comboBox_SerialStopBits.SelectedIndex;
            curDevice.iotSerial.stopBits = (SerialStopBits)Enum.ToObject(typeof(SerialStopBits), stopBitsIndex);

            byte[] buffer = curDevice.toByteArray();

            foreach (var udpServer in udpServers)
            {
                IPAddress configAddr = ((IPEndPoint)curDevice.configEndPoint).Address;
                bool sameSubnet = udpServer.Address.IsInSameSubnet(configAddr, curDevice.netmask);
                if (sameSubnet)
                    udpServer.Send(curDevice.toByteArray(), curDevice.configEndPoint);
            }
        }
    }
}
